/*
 * Interlocked.cpp
 *
 *  Created on: Nov 26, 2011
 *      Author: Lucifer
 */
#include "../pch.h"

namespace BFX
{

//////////////////////////////////////////////////////////////////////////////
#ifdef	_MSC_VER

#include <intrin.h>

// Increments (increases by one) the value of the specified 32/64 bits variable as an atomic operation.
LONG Interlocked::Increment(LONG volatile * Addend)
{
	return InterlockedIncrement(Addend);
}

// Decrements (decreases by one) the value of the specified 32/64 bits variable as an atomic operation.
LONG Interlocked::Decrement(LONG volatile * Addend)
{
	return InterlockedDecrement(Addend);
}

// Performs an atomic AND operation on the specified LONG values
LONG Interlocked::And(LONG volatile * Destination, LONG Value)
{
	return _InterlockedAnd(Destination, Value);
}

// Performs an atomic OR operation on the specified LONG values
LONG Interlocked::Or(LONG volatile * Destination, LONG Value)
{
	return _InterlockedOr(Destination, Value);
}

// Sets a 32/64 bits variable to the specified value as an atomic operation.
LONG Interlocked::Exchange(LONG volatile * Target, LONG Value)
{
	return InterlockedExchange(Target, Value);
}

// Atomically exchanges a pair of addresses.
void* Interlocked::ExchangePointer(void* volatile * Target, void * Value)
{
    return InterlockedExchangePointer(Target, Value);
}

// Performs an atomic compare-and-exchange operation on the specified values.
LONG Interlocked::CompareExchange(LONG volatile * Destination, LONG Exchange, LONG Comparand)
{
	return InterlockedCompareExchange(Destination, Exchange, Comparand);
}

// Performs an atomic compare-and-exchange operation on the specified values.
void* Interlocked::CompareExchangePointer(void* volatile * Destination, void* Exchange, void* Comparand)
{
	return InterlockedCompareExchangePointer(Destination, Exchange, Comparand);
}

#else

// Increments (increases by one) the value of the specified 32/64 bits variable as an atomic operation.
LONG Interlocked::Increment(LONG volatile * Addend)
{
	return __sync_add_and_fetch(Addend, 1);
}

// Decrements (decreases by one) the value of the specified 32/64 bits variable as an atomic operation.
LONG Interlocked::Decrement(LONG volatile * Addend)
{
	return __sync_sub_and_fetch(Addend, 1);
}

// Performs an atomic AND operation on the specified LONG values
LONG Interlocked::And(LONG volatile * Destination, LONG Value)
{
	return __sync_and_and_fetch(Destination, Value);
}

// Performs an atomic OR operation on the specified LONG values
LONG Interlocked::Or(LONG volatile * Destination, LONG Value)
{
	return __sync_or_and_fetch(Destination, Value);
}

// Sets a 32/64 bits variable to the specified value as an atomic operation.
LONG Interlocked::Exchange(LONG volatile * Target, LONG Value)
{
    __sync_synchronize();
	return __sync_lock_test_and_set(Target, Value);
}

// Atomically exchanges a pair of addresses.
void* Interlocked::ExchangePointer(void* volatile * Target, void * Value)
{
    __sync_synchronize();
    return (void*) __sync_lock_test_and_set(Target, Value);
}

// Performs an atomic compare-and-exchange operation on the specified values.
LONG Interlocked::CompareExchange(LONG volatile * Destination, LONG Exchange, LONG Comparand)
{
	return __sync_val_compare_and_swap(Destination, Comparand, Exchange);
}

// Performs an atomic compare-and-exchange operation on the specified values.
void* CompareExchangePointer(void* volatile * Destination, void* Exchange, void* Comparand)
{
	return __sync_val_compare_and_swap(Destination, Comparand, Exchange);
}

#endif	//	WIN32

} /* namespace BFX */
